﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;

namespace BusinessObjects {
  /// <summary>
  /// Child object
  /// </summary>
  public class Child : Person {

    private string nickName, minTime, maxTime, remarks;
    private int minDays, maxDays;
    private int link;
    private DateTime? birthday, dateIn, dateOut, arrivalDateTime, departureDateTime;
    private Parent mother, father;
    private TrustPersons trustPersons;
    private Schedule schedule;

    #region - Properties -

    /// <summary>
    /// Gets or sets the schedule.
    /// </summary>
    /// <value>
    /// The schedule.
    /// </value>
    public Schedule Schedule {
      get { return schedule; }
      set { schedule = value; }
    }

    /// <summary>
    /// Gets or sets the remarks.
    /// </summary>
    /// <value>
    /// The remarks.
    /// </value>
    public string Remarks {
      get { return remarks; }
      set {
        SetField( ref remarks, value, "Remarks" );
      }
    }

    /// <summary>
    /// Gets or sets the name of the nick.
    /// </summary>
    /// <value>
    /// The name of the nick.
    /// </value>
    public string NickName {
      get { return nickName; }
      set {
        SetField( ref nickName, value, "NickName" );
      }
    }

    /// <summary>
    /// Gets or sets the trust persons.
    /// </summary>
    /// <value>
    /// The trust persons.
    /// </value>
    public TrustPersons TrustPersons {
      get { return trustPersons; }
      set { trustPersons = value; }
    }

    /// <summary>
    /// Gets or sets the link.
    /// </summary>
    /// <value>
    /// The link.
    /// </value>
    public int Link {
      get { return link; }
      set {
        SetField( ref link, value, "Link" );
      }
    }

    /// <summary>
    /// Gets or sets the max time.
    /// </summary>
    /// <value>
    /// The max time.
    /// </value>
    public string MaxTime {
      get { return maxTime; }
      set {
        if ( !string.IsNullOrEmpty( value ) && value.Trim( ) == ":" ) {
          value = null;
        }
        SetField( ref maxTime, value, "MaxTime" );
      }
    }

    /// <summary>
    /// Gets or sets the min time.
    /// </summary>
    /// <value>
    /// The min time.
    /// </value>
    public string MinTime {
      get { return minTime; }
      set {
        if ( !string.IsNullOrEmpty( value ) && value.Trim( ) == ":" ) {
          value = null;
        }
        SetField( ref minTime, value, "MinTime" );
      }
    }

    /// <summary>
    /// Gets or sets the date out.
    /// </summary>
    /// <value>
    /// The date out.
    /// </value>
    public DateTime? DateOut {
      get { return dateOut; }
      set {
        SetField<DateTime?>( ref dateOut, value, "DateOut" );
      }
    }

    /// <summary>
    /// Gets or sets the date in.
    /// </summary>
    /// <value>
    /// The date in.
    /// </value>
    public DateTime? DateIn {
      get { return dateIn; }
      set {
        SetField( ref dateIn, value, "DateIn" );
      }
    }

    /// <summary>
    /// Gets or sets the birthday.
    /// </summary>
    /// <value>
    /// The birthday.
    /// </value>
    public DateTime? Birthday {
      get { return birthday; }
      set {
        SetField( ref birthday, value, "Birthday" );
      }
    }

    /// <summary>
    /// Gets or sets the max days.
    /// </summary>
    /// <value>
    /// The max days.
    /// </value>
    public int MaxDays {
      get { return maxDays; }
      set {
        SetField( ref maxDays, value, "MaxDays" );
      }
    }

    /// <summary>
    /// Gets or sets the min days.
    /// </summary>
    /// <value>
    /// The min days.
    /// </value>
    public int MinDays {
      get { return minDays; }
      set {
        SetField( ref minDays, value, "MinDays" );
      }
    }

    /// <summary>
    /// Gets the state of the child.
    /// </summary>
    /// <value>
    /// The state of the child.
    /// </value>
    public State ChildState {
      get {
        if ( DateOut.HasValue ) {
          return State.Inactive;
        } else {
          return State.Active;
        }
      }
    }

    /// <summary>
    /// Gets the state of the child active.
    /// </summary>
    /// <value>
    /// The state of the child active.
    /// </value>
    public ActiveState ChildActiveState {
      get {

        string arrivalTime = ArrivalDateTime.HasValue ? ArrivalDateTime.Value.ToShortTimeString( ).PadLeft( 5, '0' ) : "00:00";
        string departureTime = DepartureDateTime.HasValue ? DepartureDateTime.Value.ToShortTimeString( ).PadLeft( 5, '0' ) : "00:00";
        bool arrivalTimeEmpty = ( string.IsNullOrEmpty( arrivalTime ) || string.IsNullOrEmpty( arrivalTime.Trim( ) ) || arrivalTime.Trim( ) == ":" || arrivalTime == "00:00" );
        bool departureTimeEmpty = ( string.IsNullOrEmpty( departureTime ) || string.IsNullOrEmpty( departureTime.Trim( ) ) || departureTime.Trim( ) == ":" || departureTime == "00:00" );


        if ( DateOut.HasValue ) {
          return BusinessObjects.Child.ActiveState.Gone;
        } else {
          if ( departureTimeEmpty && !arrivalTimeEmpty && ArrivalDateTime <= DateTime.Now ) {
            return BusinessObjects.Child.ActiveState.Present;
          } else if ( !departureTimeEmpty && ArrivalDateTime <= DateTime.Now && DateTime.Now > DepartureDateTime ) {
            return BusinessObjects.Child.ActiveState.Present;
          } else {
            return Child.ActiveState.Absent;
          }
        }
      }
    }

    /// <summary>
    /// Gets or sets the father.
    /// </summary>
    /// <value>
    /// The father.
    /// </value>
    public Parent Father {
      get { return father; }
      set { father = value; }
    }

    /// <summary>
    /// Gets or sets the mother.
    /// </summary>
    /// <value>
    /// The mother.
    /// </value>
    public Parent Mother {
      get { return mother; }
      set { mother = value; }
    }

    /// <summary>
    /// Gets or sets the departure date time.
    /// </summary>
    /// <value>
    /// The departure date time.
    /// </value>
    public DateTime? DepartureDateTime {
      get { return departureDateTime; }
      set { departureDateTime = value; }
    }

    /// <summary>
    /// Gets or sets the arrival date time.
    /// </summary>
    /// <value>
    /// The arrival date time.
    /// </value>
    public DateTime? ArrivalDateTime {
      get { return arrivalDateTime; }
      set { arrivalDateTime = value; }
    }

    #endregion

    #region - Constructors-

    /// <summary>
    /// Initializes a new instance of the <see cref="Child"/> class.
    /// </summary>
    public Child( ) {
      this.Mother = new Parent( );
      this.Mother.PropertyChanged += new PropertyChangedEventHandler( Mother_Changed );
      this.Mother.Address = new Address( );
      this.Mother.Address.PropertyChanged += new PropertyChangedEventHandler( MotherAddress_Changed );
      this.Mother.Employer = new ParentEmployer( );
      this.Mother.Employer.PropertyChanged += new PropertyChangedEventHandler( MotherEmployer_Changed );
      this.Mother.Employer.Address = new Address( );
      this.Mother.Employer.Address.PropertyChanged += new PropertyChangedEventHandler( MotherEmployerAddress_Changed );
      this.Father = new Parent( );
      this.Father.PropertyChanged += new PropertyChangedEventHandler( Father_Changed );
      this.Father.Address = new Address( );
      this.Father.Address.PropertyChanged += new PropertyChangedEventHandler( FatherAddress_Changed );
      this.Father.Employer = new ParentEmployer( );
      this.Father.Employer.PropertyChanged += new PropertyChangedEventHandler( FatherEmployer_Changed );
      this.Father.Employer.Address = new Address( );
      this.Father.Employer.Address.PropertyChanged += new PropertyChangedEventHandler( FatherEmployerAddress_Changed );
      this.TrustPersons = new TrustPersons( );
      this.Schedule = new Schedule( );
      this.Schedule.PropertyChanged += new PropertyChangedEventHandler( Schedule_Changed );
    }


    /// <summary>
    /// Initializes a new instance of the <see cref="Child"/> class.
    /// </summary>
    /// <param name="id">The id.</param>
    /// <param name="name">The name.</param>
    public Child( int id, string name )
      : this( ) {
      this.Id = id;
      this.Name = name;
    }

    #endregion

    #region - Enums -

    /// <summary>
    /// Overall state of a child
    /// </summary>
    public enum State : byte {
      Active = 0,
      Inactive = 1
    }

    /// <summary>
    /// Active state of a child
    /// </summary>
    public enum ActiveState : byte {
      Present = 0,
      Absent = 1,
      Gone = 2
    }

    #endregion

    #region - Methods -

    /// <summary>
    /// Copies this instance.
    /// </summary>
    /// <returns></returns>
    public Child Copy( ) {
      Child childCopy = new Child( );
      childCopy.Id = this.Id;
      childCopy.Name = this.Name;
      childCopy.FirstName = this.FirstName;
      childCopy.NickName = this.NickName;
      childCopy.DateIn = this.DateIn;
      childCopy.DateOut = this.DateOut;
      childCopy.Birthday = this.Birthday;
      childCopy.MinDays = this.MinDays;
      childCopy.MaxDays = this.MaxDays;
      childCopy.MinTime = this.MinTime;
      childCopy.MaxTime = this.MaxTime;
      childCopy.Photo = this.Photo;
      childCopy.Link = this.Link;

      childCopy.Mother.Id = this.Mother.Id;
      childCopy.Mother.Name = this.Mother.Name;
      childCopy.Mother.FirstName = this.Mother.FirstName;
      childCopy.Mother.Phone = this.Mother.Phone;
      childCopy.Mother.Gsm = this.Mother.Gsm;
      childCopy.Mother.Email = this.Mother.Email;
      childCopy.Mother.NationalNumber = this.Mother.NationalNumber;
      childCopy.Mother.Photo = this.Mother.Photo;
      childCopy.Mother.BasicPrice = this.Mother.BasicPrice;
      childCopy.Mother.MainAddress = this.Mother.MainAddress;
      childCopy.Mother.HasChanged = this.Mother.HasChanged;
      childCopy.Mother.Address.City = this.Mother.Address.City;
      childCopy.Mother.Address.CountryName = this.Mother.Address.CountryName;
      childCopy.Mother.Address.CountryCode = this.Mother.Address.CountryCode;
      childCopy.Mother.Address.CountryId = this.Mother.Address.CountryId;
      childCopy.Mother.Address.Street = this.Mother.Address.Street;
      childCopy.Mother.Address.Zipcode = this.Mother.Address.Zipcode;
      childCopy.Mother.Address.ZipcodeId = this.Mother.Address.ZipcodeId;
      childCopy.Mother.Address.HasChanged = this.Mother.Address.HasChanged;
      childCopy.Mother.Employer.Id = this.Mother.Employer.Id;
      childCopy.Mother.Employer.Name = this.Mother.Employer.Name;
      childCopy.Mother.Employer.Phone = this.Mother.Employer.Phone;
      childCopy.Mother.Employer.HasChanged = this.Mother.Employer.HasChanged;
      childCopy.Mother.Employer.Address.City = this.Mother.Employer.Address.City;
      childCopy.Mother.Employer.Address.CountryCode = this.Mother.Employer.Address.CountryCode;
      childCopy.Mother.Employer.Address.CountryName = this.Mother.Employer.Address.CountryName;
      childCopy.Mother.Employer.Address.CountryId = this.Mother.Employer.Address.CountryId;
      childCopy.Mother.Employer.Address.Street = this.Mother.Employer.Address.Street;
      childCopy.Mother.Employer.Address.Zipcode = this.Mother.Employer.Address.Zipcode;
      childCopy.Mother.Employer.Address.ZipcodeId = this.Mother.Employer.Address.ZipcodeId;
      childCopy.Mother.Employer.Address.HasChanged = this.Mother.Employer.Address.HasChanged;

      childCopy.Father.Id = this.Father.Id;
      childCopy.Father.Name = this.Father.Name;
      childCopy.Father.FirstName = this.Father.FirstName;
      childCopy.Father.Phone = this.Father.Phone;
      childCopy.Father.Gsm = this.Father.Gsm;
      childCopy.Father.Email = this.Father.Email;
      childCopy.Father.NationalNumber = this.Father.NationalNumber;
      childCopy.Father.Photo = this.Father.Photo;
      childCopy.Father.MainAddress = this.Father.MainAddress;
      childCopy.Father.HasChanged = this.Father.HasChanged;
      childCopy.Father.Address.City = this.Father.Address.City;
      childCopy.Father.Address.CountryName = this.Father.Address.CountryName;
      childCopy.Father.Address.CountryCode = this.Father.Address.CountryCode;
      childCopy.Father.Address.CountryId = this.Father.Address.CountryId;
      childCopy.Father.Address.Street = this.Father.Address.Street;
      childCopy.Father.Address.Zipcode = this.Father.Address.Zipcode;
      childCopy.Father.Address.ZipcodeId = this.Father.Address.ZipcodeId;
      childCopy.Father.Address.HasChanged = this.Father.Address.HasChanged;
      childCopy.Father.Employer.Id = this.Father.Employer.Id;
      childCopy.Father.Employer.Name = this.Father.Employer.Name;
      childCopy.Father.Employer.Phone = this.Father.Employer.Phone;
      childCopy.Father.Employer.HasChanged = this.Father.Employer.HasChanged;
      childCopy.Father.Employer.Address.City = this.Father.Employer.Address.City;
      childCopy.Father.Employer.Address.CountryCode = this.Father.Employer.Address.CountryCode;
      childCopy.Father.Employer.Address.CountryName = this.Father.Employer.Address.CountryName;
      childCopy.Father.Employer.Address.CountryId = this.Father.Employer.Address.CountryId;
      childCopy.Father.Employer.Address.Street = this.Father.Employer.Address.Street;
      childCopy.Father.Employer.Address.Zipcode = this.Father.Employer.Address.Zipcode;
      childCopy.Father.Employer.Address.ZipcodeId = this.Father.Employer.Address.ZipcodeId;
      childCopy.Father.Employer.Address.HasChanged = this.Father.Employer.Address.HasChanged;

      foreach ( TrustPerson person in this.TrustPersons ) {
        TrustPerson personCopy = new TrustPerson( );
        personCopy.Id = person.Id;
        personCopy.Name = person.Name;
        personCopy.FirstName = person.FirstName;
        personCopy.Phone = person.Phone;
        personCopy.Gsm = person.Gsm;
        personCopy.Email = person.Email;
        personCopy.NationalNumber = person.NationalNumber;
        personCopy.Photo = person.Photo;
        personCopy.HasChanged = person.HasChanged;
        personCopy.Address.City = person.Address.City;
        personCopy.Address.CountryName = person.Address.CountryName;
        personCopy.Address.CountryCode = person.Address.CountryCode;
        personCopy.Address.CountryId = person.Address.CountryId;
        personCopy.Address.Street = person.Address.Street;
        personCopy.Address.Zipcode = person.Address.Zipcode;
        personCopy.Address.ZipcodeId = person.Address.ZipcodeId;
        personCopy.Address.HasChanged = person.Address.HasChanged;
        childCopy.TrustPersons.Add( personCopy );
      }

      childCopy.Schedule.Id = this.Schedule.Id;
      childCopy.Schedule.HasChanged = this.Schedule.HasChanged;
      childCopy.Schedule.Type = this.Schedule.Type;
      childCopy.Schedule.Week1MoFrom = this.Schedule.Week1MoFrom;
      childCopy.Schedule.Week1MoTo = this.Schedule.Week1MoTo;
      childCopy.Schedule.Week1TuFrom = this.Schedule.Week1TuFrom;
      childCopy.Schedule.Week1TuTo = this.Schedule.Week1TuTo;
      childCopy.Schedule.Week1WeFrom = this.Schedule.Week1WeFrom;
      childCopy.Schedule.Week1WeTo = this.Schedule.Week1WeTo;
      childCopy.Schedule.Week1ThFrom = this.Schedule.Week1ThFrom;
      childCopy.Schedule.Week1ThTo = this.Schedule.Week1ThTo;
      childCopy.Schedule.Week1FrFrom = this.Schedule.Week1FrFrom;
      childCopy.Schedule.Week1FrTo = this.Schedule.Week1FrTo;

      childCopy.Schedule.Week2MoFrom = this.Schedule.Week2MoFrom;
      childCopy.Schedule.Week2MoTo = this.Schedule.Week2MoTo;
      childCopy.Schedule.Week2TuFrom = this.Schedule.Week2TuFrom;
      childCopy.Schedule.Week2TuTo = this.Schedule.Week2TuTo;
      childCopy.Schedule.Week2WeFrom = this.Schedule.Week2WeFrom;
      childCopy.Schedule.Week2WeTo = this.Schedule.Week2WeTo;
      childCopy.Schedule.Week2ThFrom = this.Schedule.Week2ThFrom;
      childCopy.Schedule.Week2ThTo = this.Schedule.Week2ThTo;
      childCopy.Schedule.Week2FrFrom = this.Schedule.Week2FrFrom;
      childCopy.Schedule.Week2FrTo = this.Schedule.Week2FrTo;

      childCopy.Schedule.Week3MoFrom = this.Schedule.Week3MoFrom;
      childCopy.Schedule.Week3MoTo = this.Schedule.Week3MoTo;
      childCopy.Schedule.Week3TuFrom = this.Schedule.Week3TuFrom;
      childCopy.Schedule.Week3TuTo = this.Schedule.Week3TuTo;
      childCopy.Schedule.Week3WeFrom = this.Schedule.Week3WeFrom;
      childCopy.Schedule.Week3WeTo = this.Schedule.Week3WeTo;
      childCopy.Schedule.Week3ThFrom = this.Schedule.Week3ThFrom;
      childCopy.Schedule.Week3ThTo = this.Schedule.Week3ThTo;
      childCopy.Schedule.Week3FrFrom = this.Schedule.Week3FrFrom;
      childCopy.Schedule.Week3FrTo = this.Schedule.Week3FrTo;

      childCopy.Schedule.Week4MoFrom = this.Schedule.Week4MoFrom;
      childCopy.Schedule.Week4MoTo = this.Schedule.Week4MoTo;
      childCopy.Schedule.Week4TuFrom = this.Schedule.Week4TuFrom;
      childCopy.Schedule.Week4TuTo = this.Schedule.Week4TuTo;
      childCopy.Schedule.Week4WeFrom = this.Schedule.Week4WeFrom;
      childCopy.Schedule.Week4WeTo = this.Schedule.Week4WeTo;
      childCopy.Schedule.Week4ThFrom = this.Schedule.Week4ThFrom;
      childCopy.Schedule.Week4ThTo = this.Schedule.Week4ThTo;
      childCopy.Schedule.Week4FrFrom = this.Schedule.Week4FrFrom;
      childCopy.Schedule.Week4FrTo = this.Schedule.Week4FrTo;

      childCopy.HasChanged = this.HasChanged;
      return childCopy;
    }

    /// <summary>
    /// Marks the object as clean.
    /// </summary>
    public override void MarkClean( ) {
      base.MarkClean( );
      this.HasChanged = false;

      this.Mother.HasChanged = false;
      this.Mother.Address.HasChanged = false;
      this.Mother.Employer.HasChanged = false;
      this.Mother.Employer.Address.HasChanged = false;

      this.Father.HasChanged = false;
      this.Father.Address.HasChanged = false;
      this.Father.Employer.HasChanged = false;
      this.Father.Employer.Address.HasChanged = false;

      this.Schedule.HasChanged = false;

      foreach ( TrustPerson person in this.TrustPersons ) {
        person.HasChanged = false;
        person.Address.HasChanged = false;
      }
    }

    #endregion

    #region - Events -

    void Schedule_Changed( object sender, PropertyChangedEventArgs e ) {
      if ( Schedule.HasChanged ) {
        this.HasChanged = this.Schedule.HasChanged;
      }
    }

    void FatherEmployerAddress_Changed( object sender, PropertyChangedEventArgs e ) {
      if ( Father.Employer.Address.HasChanged ) {
        this.HasChanged = this.Father.Employer.Address.HasChanged;
      }
    }

    void FatherEmployer_Changed( object sender, PropertyChangedEventArgs e ) {
      if ( Father.Employer.HasChanged ) {
        this.HasChanged = this.Father.Employer.HasChanged;
      }
    }

    void FatherAddress_Changed( object sender, PropertyChangedEventArgs e ) {
      if ( Father.Address.HasChanged ) {
        this.HasChanged = this.Father.Address.HasChanged;
      }
    }

    void Father_Changed( object sender, PropertyChangedEventArgs e ) {
      if ( Father.HasChanged ) {
        this.HasChanged = this.Father.HasChanged;
      }
    }

    void MotherEmployerAddress_Changed( object sender, PropertyChangedEventArgs e ) {
      if ( Mother.Employer.Address.HasChanged ) {
        this.HasChanged = this.Mother.Employer.Address.HasChanged;
      }
    }

    void MotherEmployer_Changed( object sender, PropertyChangedEventArgs e ) {
      if ( Mother.Employer.HasChanged ) {
        this.HasChanged = this.Mother.Employer.HasChanged;
      }
    }

    void MotherAddress_Changed( object sender, PropertyChangedEventArgs e ) {
      if ( Mother.Address.HasChanged ) {
        this.HasChanged = this.Mother.Address.HasChanged;
      }
    }

    void Mother_Changed( object sender, PropertyChangedEventArgs e ) {
      if ( Mother.HasChanged ) {
        this.HasChanged = this.Mother.HasChanged;
      }
    }

    #endregion

  }
}
